home *** CD-ROM | disk | FTP | other *** search
- /*============================================================================*\
- * PopUpTkl.c - Popup menu tackler
- *
- * PopUpTkl.c contains the code to process the mPopUpMsg message from the Menu
- * Manager. This involves calculating the rectangle that the popup menu should
- * appear in.
- \*============================================================================*/
-
-
- /******************************************************************************\
- * Header Files
- \******************************************************************************/
-
- #include <Memory.h>
- #include <Menus.h>
- #include <OSUtils.h>
- #include <Script.h>
- #include <Types.h>
- #include "Concordia.h"
- #include "DrawTkl.h"
- #include "PopUpTkl.h"
- #include "SizeTkl.h"
-
-
- /******************************************************************************\
- * Prototypes
- \******************************************************************************/
-
- void FindScreen (Rect *menuRect,
- Rect *retScreenRect);
-
-
- #pragma segment Main
- /******************************************************************************\
- * DoPopUpMsg - Calculate a popup menu's rectangle
- *
- * DoPopUpMsg calculates the menu rectangle for the popup menu specified by
- * TheMenu. This rectangle is returned in MenuRect. The top-left corner of the
- * menu item specified by PopUpItem will appear at the coordinates given by
- * TopPos and LeftPos. The vertical coordinate of the top of the menu's
- * rectangle is returned. If the menu runs off of the screen, its size and
- * position will be adjusted.
- *
- * Coding Notes
- * #A# - This loop calculates the total height of the menu (Height), the width of
- * the menu (Width), the height of the tallest item in the menu
- * (MaxHeight), and the distance from the top of the menu to the item
- * specified by PopUpItem (ItemPos).
- * #B# - Read this as: if the height of this menu is too small to display the
- * tallest menu item and two scroll icons,then. . .
- * #C# - If the height of the tallest menu item plus two scroll icons is more
- * than the height of the entire menu, adjust the menu's position so that
- * the entire menu is displayed. Otherwise, set the height of the menu to
- * the height of the tallest item plus two scroll icons.
- \******************************************************************************/
-
- short
- DoPopUpMsg (TheMenu, MenuRect, TopPos, LeftPos, PopUpItem)
- MenuHandle TheMenu; //=> Menu to size >>
- Rect *MenuRect; //-> Menu's rectangle <<
- short TopPos; //Vertical screen position of popup item >>
- short LeftPos; //Horizontal screen position of popup item >>
- short PopUpItem; //Item to appear at LeftPos, TopPos >>
- {
- Str255 *ItemString; //-> Item's string
- ItemInfoPtr ItemInfo; //-> Item info
- short TestWidth; //Width of item to test
- short TestHeight; //Width of menu to test
- short Height; //Height of menu
- short Width; //Width of menu
- short MaxHeight; //Height of tallest menu item
- short ItemInd; //Item number of item being checked.
- short ItemPos; //Dist from menu top to PopUpItem in pixels
- short MenuTop; //Coord of top of menu rect, even if off screen
- Rect ScrnRect; //Rectangle of screen minus menu bar and margins
- short HeightAdj; //New coord of menu top/bottom if small menu
-
- Height = Width = MaxHeight = 0;
- ItemInd = 1;
- ItemPos = 0;
- HLock ((Handle) TheMenu);
- ItemString = (Str255 *) (**TheMenu).menuData;
- ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
- while ((*ItemString) [0] != (char) 0) //#A#
- {
- ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString));
- TestHeight = CalcItemHeight (*ItemString, ItemInfo);
- TestWidth = CalcItemWidth (*ItemString, ItemInfo);
- if (ItemInd == PopUpItem)
- ItemPos = Height;
- if (TestWidth > Width)
- Width = TestWidth;
- if (TestHeight > MaxHeight)
- MaxHeight = TestHeight;
- Height += TestHeight;
- ItemInd += 1;
- ItemString = (Str255 *) (ItemInfo + 1);
- }
- HUnlock ((Handle) TheMenu);
- MenuTop = TopPos - ItemPos;
- MenuRect->left = LeftPos;
- MenuRect->top = MenuTop;
- MenuRect->right = MenuRect->left + Width;
- MenuRect->bottom = MenuRect->top + Height;
- FindScreen (MenuRect, &ScrnRect);
- InsetRect (&ScrnRect, scrnMargin, scrnMargin);
- if (MenuRect->top < ScrnRect.top)
- {
- MenuRect->top = ScrnRect.top;
- if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) <
- MaxHeight) //#B#
- {
- if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C#
- HeightAdj = MenuRect->top + Height;
- else
- HeightAdj = MenuRect->top + MaxHeight + (short) (2 *
- scrlIconHeight);
- MenuTop += HeightAdj - MenuRect->bottom;
- MenuRect->bottom = HeightAdj;
- }
- }
- if (MenuRect->right > ScrnRect.right)
- OffsetRect (MenuRect, ScrnRect.right - MenuRect->right, 0);
- if (MenuRect->left < ScrnRect.left)
- OffsetRect (MenuRect, ScrnRect.left - MenuRect->left, 0);
- if (MenuRect->bottom > ScrnRect.bottom)
- {
- MenuRect->bottom = ScrnRect.bottom;
- if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) <
- MaxHeight) //#B#
- {
- if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C#
- HeightAdj = MenuRect->bottom - Height;
- else
- HeightAdj = MenuRect->bottom - MaxHeight - (short) (2 *
- scrlIconHeight);
- MenuTop -= MenuRect->top - HeightAdj;
- MenuRect->top = HeightAdj;
- }
- }
- return MenuTop;
- }
-
-
- /******************************************************************************\
- * Private: FindScreen - Find rectangle of the screen containing most of the menu
- *
- * Color QuickDraw machines can have more than one screen, and pop-up menus
- * should appear on the screen that contains the most of the menu’s area. This
- * function returns the rectangle of the screen (in global coordinates) that
- * contains most of the menu whose rectangle (also in global coordinates) is
- * passed in the menuRect parameter. The screen’s rectangle is returned in the
- * retScreenRect parameter. If the screen that contains the most of the menu is
- * the main screen (i.e. the screen with the menu bar), then the height of the
- * menu bar is added to the top of retScreenRect, effectively removing the menu
- * bar from the rectangle. When Concordia is used on a machine without Color
- * QuickDraw, then the rectangle of the main screen is always returned. Non-
- * Color QuickDraw machines with more than one screen (available from third-party
- * manufacturers) patch QuickDraw to support their screens, and it’s impossible
- * to determine the rectangles of the auxiliary screens without using
- * manufacturer-specific techniques. Because of this, Concordia does not take
- * advantage of auxiliary screens on non-Color QuickDraw machines.
- *
- * The rectangles of all attached screens are determined through the GDevice list
- * that’s maintained by the system. There’s one GDevice in the list for every
- * screen attached to the system. GDevice routines only exist on Color QuickDraw
- * machines, so the first thing that FindScreen does is to determine whether it’s
- * running on a machine that has Color QuickDraw or not. If it’s not, then the
- * screen rectangle is taken from the screenBits.bounds QuickDraw global. If
- * Color QuickDraw is available, then the GDevice list is used to determine the
- * appropriate screen.
- *
- * The first GDevice in the GDevice list is retrieved from the GetDeviceList
- * function. The next GDevice in the list is retrieved from the GetNextDevice
- * function. Through these two functions, every GDevice in the GDevice list can
- * be retrieved.
- *
- * For every GDevice in the list, the area of intersection between the menu’s
- * rectangle and the screen’s rectangle (found in the gdRect field of the GDevice
- * structure) is calculated. If the area of intersection is the greatest found
- * so far, then it and its GDevice is saved, and the rectangle of that screen is
- * placed into retScreenRect.
- *
- * After every GDevice in the GDevice list has been checked, the GDevice for the
- * screen containing most of the menu’s rectangle is checked to see if it’ the
- * GDevice for the main screen. This is done by comparing the GDevice handle
- * against the handle for the main screen’s GDevice returned by GetMainDevice.
- * If the GDevice is in fact the main screen’s GDevice, then the height of the
- * menu bar is removed from retScreenRect.
- \******************************************************************************/
-
- static void
- FindScreen (menuRect, retScreenRect)
- Rect *menuRect; /* Menu rectangle before processing for screen */
- Rect *retScreenRect; /* Returns rectangle of screen appropriate for menu */
- {
- GDHandle aGDevice; /* Handle to each screen’s GDevice */
- GDHandle maxGDevice; /* Handle to GDevice containing most of menu */
- long area; /* Menu rect/screen rect intersection area */
- long maxArea; /* Max menu rect/screen rect intersect area found */
- Rect commonRect; /* Intersection between menu rect and screen rect */
- SysEnvRec environs; /* Current running environment */
-
- /* Determine whether Color QuickDraw is implemented or not */
- (void) SysEnvirons (curSysEnvVers, /*<*/&environs);
-
- /* Use GDevices if Color QuickDraw is implemented, else use screenBits */
- if (environs.hasColorQD)
- {
- /* Assume max intersection area is 0 and get first GDevice in list */
- maxArea = 0L;
- maxGDevice = nil;
- aGDevice = GetDeviceList ();
-
- /* Loop through all screen GDevices */
- while (aGDevice != nil)
- {
- /* Calc area of intersection between menu rect and screen rect */
- SectRect (menuRect, &(**aGDevice).gdRect, /*<*/&commonRect);
- area = (long) (commonRect.bottom - commonRect.top) * (commonRect.
- right - commonRect.left);
-
- /* If max area found so far, get screen’s rect and save area */
- if (area > maxArea)
- {
- *retScreenRect = (**aGDevice).gdRect;
- maxGDevice = aGDevice;
- maxArea = area;
- }
-
- /* Go to the next GDevice in the list */
- aGDevice = GetNextDevice (aGDevice);
- }
-
- /* If GDevice with most of menu is main screen, remove MBar height */
- if (maxGDevice == GetMainDevice ())
- retScreenRect->top += GetMBarHeight ();
- }
- else
- {
- *retScreenRect = qdGlobPtr->screenBits.bounds;
- retScreenRect->top += GetMBarHeight ();
- }
- }
-